package com.yesep.learn.design.creational.factory;

import com.yesep.learn.design.common.*;
import com.yesep.learn.design.common.pojo.*;
import com.yesep.learn.design.common.util.*;

/**
 * 工厂模式（Factory Pattern）是一种创建型设计模式，它提供了一种创建对象的最佳方式，而不必在每次需要对象时都明确指定具体的类。
 * 工厂模式定义一个用于创建对象的接口，但让子类决定要实例化的类是哪一个。工厂模式让类的实例化推迟到子类中进行。
 * <p>
 * 工厂模式主要分为三种类型：简单工厂模式（Simple Factory Pattern）、工厂方法模式（Factory Method Pattern）和抽象工厂模式（Abstract Factory Pattern）。
 * <p>
 * 1. 简单工厂模式（Simple Factory Pattern）
 * 简单工厂模式又称为静态工厂方法模式，它由一个工厂类根据传入的参数，决定实例化哪一个产品类的实例。
 * 这种模式的缺点是当需要增加新的产品类时，需要修改工厂类，违背了开闭原则（对扩展开放，对修改关闭）。
 * <p>
 * 2. 工厂方法模式（Factory Method Pattern）
 * 工厂方法模式定义了一个创建对象的接口，但让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。
 * 这样，类的实例化就在子类中完成了，遵循了依赖倒转原则和里氏替换原则，并且增加了系统的灵活性和可扩展性。
 * <p>
 * 3. 抽象工厂模式（Abstract Factory Pattern）
 * 抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口，而无需指定它们具体的类。
 * 抽象工厂模式用于创建相关或依赖对象的家族，而不需要明确指定具体类。
 * 它允许客户使用抽象的接口来创建一组相关的对象，而不需要知道实际输出的具体类是什么。
 * 这样客户就可以从具体的产品中被解耦出来。
 * <p>
 * 优缺点
 * <p>
 * 优点：
 * 工厂模式使得对象的创建与具体的使用者分离，降低了系统的耦合度。
 * 提高了系统的灵活性和可扩展性，新增产品类时不需要修改现有代码。
 * 隐藏了对象的创建细节，客户端只需要通过简单调用工厂的接口就可以得到所需要的对象。
 * <p>
 * 缺点：
 * 增加了系统的复杂度，因为需要引入抽象工厂类、抽象产品类和具体产品类等多个类。
 * 当系统中具体产品类非常多时，工厂类也会变得很多，增加系统的管理难度。
 * 应用场景
 * 当一个类不知道它所必须创建的对象的类的时候。
 * 当一个类希望由它的子类来指定它所创建的对象的时候。
 * 当类将创建对象的职责委托给多个帮助子类中的某一个，并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
 */
public class Main {

    public static void main(String[] args) throws Exception {
        //工厂方法模式
        Dog dog = DemoUtil.createDog();
        dog.move();
        Cat cat = DemoUtil.createCat();
        cat.move();
        Bird bird = DemoUtil.createBird();
        bird.move();
        Bee bee = DemoUtil.createBee();
        bee.move();
        //抽象工厂模式
        IAnimalAbstractFactory animalAbstractFactory = new AnimalAbstractFactory();
        dog = animalAbstractFactory.createAnimal("旺财 1", AnimalType.Dog);
        dog.move();
        bee = animalAbstractFactory.createAnimal("园丁 1", AnimalType.Bee);
        bee.move();

        //简单工厂方法模式
        dog = (Dog) AnimalSimpleFactory.createAnimal(AnimalType.Dog);
        dog.move();
        dog.speak();
        bee = (Bee) AnimalSimpleFactory.createAnimal(AnimalType.Bee);
        bee.move();
        bee.speak();
    }
}
